#![cfg_attr(debug_assertions, allow(dead_code, unused_imports, unused_variables, unused_mut))]
//use colored::Colorize;
use std::env;
use std::fs;
use std::path::Path;

// FFI 3rd libs 的路径; openblas 版本
const LIB_DIR_STATIC: &str = "../../3rdlibs/lapack_open/lib";
const LIB_DIR_DYNAMIC: &str = "../../3rdlibs/lapack_open/bin";

fn main() {
    if !cfg!(target_os = "windows") {
        println!("cargo:warning=This build script is only executed on Windows platforms.");
        return;
    }

    // 检查依赖库目录是否存在
    let static_path = Path::new(LIB_DIR_STATIC);
    let dynamic_path = Path::new(LIB_DIR_DYNAMIC);

    if !static_path.exists() && !dynamic_path.exists() {
        panic!(
            "{}",
            format!(
                "======================================
    Dependency library directories not found!
    Please download LAPACK and BLAS libraries and place them in the following directories:
    Static library directory: {}
    Dynamic library directory: {}",
                static_path.display(),
                dynamic_path.display()
            )
        );
    }

    // 获取目标路径
    let _out_dir = env::var("OUT_DIR").unwrap();

    #[cfg(any())]
    {
        let te_path = env::var("PATH").unwrap_or_default();
        println!("cargo:warning=env PATH={:?}", &te_path);
    }
    #[cfg(any())]
    {
        for (key, value) in env::vars() {
            println!("cargo:warning={} => {}", key, value);
        }
    }
    // 检查环境变量或命令行参数来决定使用静态链接还是动态链接
    let ltype_read = env::var("LINK_TYPE");
    println!("cargo:warning=------env.LINK_TYPE={:?}", &ltype_read);
    let link_type = ltype_read.unwrap_or_else(|_| "dynamic".to_string());
    //let link_type = "static".to_string();
    //let link_type = "dynamic".to_string();
    match link_type.as_str() {
        "static" => {
            // 静态链接
            println!("cargo:warning=------Using static linking for LAPACK and BLAS.");
            println!("cargo:rustc-link-search=native={}", LIB_DIR_STATIC);
            //=== msvc link.exe 使用 msys2 下的 liblapack.dll.a 和 libopenblas.dll.a 时候, 必须使用 +verbatim
            //#[cfg(any())]
            {
                println!("cargo:rustc-link-lib=static:+verbatim=liblapack.a");
                println!("cargo:rustc-link-lib=static:+verbatim=libopenblas.a");
                //println!("cargo:rustc-link-lib=static:+verbatim=libgfortran.a");
                println!("cargo:rustc-link-lib=static:+verbatim=libmingwex.a");
                println!("cargo:rustc-link-lib=static:+verbatim=libgcc_s.a");
                println!("cargo:rustc-link-lib=static:+verbatim=libgcc.a");
            }
        }
        "dynamic" => {
            // 动态链接
            println!("cargo:warning=------Using dynamic linking for LAPACK and BLAS.");
            println!("cargo:rustc-link-search=native={}", LIB_DIR_DYNAMIC);

            // 复制 DLL 文件到目标目录
            let out_dir = env::var("OUT_DIR").unwrap();
            let target_dir = Path::new(&out_dir).ancestors().nth(3).unwrap();
            let dll_source_dir = Path::new(LIB_DIR_DYNAMIC);
            // 复制所有 DLL 文件到目标目录
            if let Ok(entries) = fs::read_dir(&dll_source_dir) {
                for entry in entries {
                    if let Ok(entry) = entry {
                        let path = entry.path();
                        if path.extension().map_or(false, |ext| ext == "dll") {
                            let file_name = path.file_name().unwrap();
                            let target = target_dir.join(file_name);
                            if let Err(e) = fs::copy(&path, &target) {
                                println!("cargo:warning=Failed to copy {:?}: {}", file_name, e);
                            }
                        }
                    }
                }
            } else {
                println!("cargo:warning=Failed to read directory: {:?}", &dll_source_dir);
            }

            // 这么写也可以; +verbatim 表示 rustc 本身不会在库名中添加任何目标指定的库前缀或后缀
            // (如 lib 或 .a), 并会尽量要求链接器也这样做.
            #[cfg(any())]
            {
                println!("cargo:rustc-link-lib=dylib:+verbatim=liblapack.lib");
                println!("cargo:rustc-link-lib=dylib:+verbatim=libblas.lib");
            }

            // 这么写会链接失败, msvc link.exe 不会添加 lib 前缀,
            // 会去寻找 lapack.dll 对应的 lapack.lib 导入库(importlib), 但是找不到
            #[cfg(any())]
            {
                println!("cargo:rustc-link-lib=dylib=lapack");
                println!("cargo:rustc-link-lib=dylib=openblas");
            }

            // 通常这么写, msvc link.exe 会自动加上 .lib 后缀, 寻找dll对应的importlib
            #[cfg(any())]
            {
                println!("cargo:rustc-link-lib=dylib=liblapack");
                println!("cargo:rustc-link-lib=dylib=libblas");
            }

            // msvc 不会识别 msys2 下的 liblapack.dll.a 和 libopenblas.dll.a
            // 会报错: 找不到 lapack.dll.lib, openblas.dll.lib
            #[cfg(any())]
            {
                println!("cargo:rustc-link-lib=dylib=liblapack.dll");
                println!("cargo:rustc-link-lib=dylib=libopenblas.dll");
            }

            //=== msvc link.exe 使用 msys2 下的 liblapack.dll.a 和 libopenblas.dll.a 时候, 必须使用 +verbatim
            //#[cfg(any())]
            {
                println!("cargo:rustc-link-lib=dylib:+verbatim=liblapack.dll.a");
                println!("cargo:rustc-link-lib=dylib:+verbatim=libopenblas.dll.a");
            }
        }
        _ => {
            panic!("Invalid LINK_TYPE. Use 'static' or 'dynamic'.");
        }
    }

    // 防止重新编译
    println!("cargo:rerun-if-changed=build.rs");
}
